package timing.ukulele.oss;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import timing.ukulele.oss.config.OSSProperties;
import timing.ukulele.oss.exceptions.UkuleleOSSException;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * UkuleleOSS标准调用接口
 *
 * @author 11697
 */
public interface UkuleleOSSTemplate {

    default void init(OSSProperties config) {
    }

    default void close() {
    }

    /**
     * 文件后缀白名单
     *
     * @return
     */
    String getFileTypeWhiteList();

    /**
     * 将字符串切割成list，支持|或者,分割线
     *
     * @param listStr
     * @return
     */
    default List<String> splitToList(String listStr) {
        List<String> list = new ArrayList<>();
        if (StringUtils.isEmpty(listStr)) {
            return list;
        }
        if (listStr.contains("|")) {
            list = Arrays.asList(listStr.split("\\|"));
        }
        if (listStr.contains(",")) {
            list = Arrays.asList(listStr.split(","));
        }
        List<String> upperList = new ArrayList<>();
        upperList.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList()));
        return upperList;
    }

    /**
     * 获取上传文件的文件后缀
     *
     * @param file
     * @return .png
     */
    default String getSuffixName(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isEmpty(originalFilename) || !originalFilename.contains(".")) {
            throw new UkuleleOSSException("original file name or type is empty");
        }
        //文件后缀名
        String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
        return suffixName;
    }

    /**
     * 判断文件的后缀名是否在白名单中，存在返回true
     *
     * @param file
     * @return
     */
    default boolean isAllowedFileSuffixName(MultipartFile file) {
        String sufixwhiteListStr = getFileTypeWhiteList();
        if (sufixwhiteListStr == null) {
            return true;
        }
        sufixwhiteListStr = sufixwhiteListStr.trim();
        if (!StringUtils.hasText(sufixwhiteListStr)) {
            return true;
        }
        String suffixName = getSuffixName(file).toUpperCase();
        // 文件后缀白名单校验(不区分大小写)
        List<String> sufixwhiteList = splitToList(sufixwhiteListStr);
        return sufixwhiteList.contains(suffixName);
    }

    /**
     * 判断文件后缀名是否在白名单中，如果不在报异常，中止文件保存
     *
     * @param file
     */
    default void checkFileSuffixName(MultipartFile file) {
        // 是否是允许的文件后缀
        boolean allowedFileSuffix = isAllowedFileSuffixName(file);
        if (allowedFileSuffix == false) {
            throw new UkuleleOSSException("文件类型无法识别，请确认上传文件！");
        }
    }

    /**
     * 输入参数为前端文件上传对象MultipartFile
     * 返回的是新文件名，下载删除需要
     */
    default String uploadFileByInputStream(MultipartFile file, Boolean isPrivate) throws UkuleleOSSException, IOException {
        //判断文件后缀名是否在白名单中
        checkFileSuffixName(file);

        String suffixName = getSuffixName(file);
        String fileId = UUID.randomUUID().toString();
        fileId = fileId.replaceAll("-", "");
        String fileObjectName = fileId + suffixName;
        return uploadFileByInputStream(file, fileObjectName, isPrivate);
    }

    /**
     * 输入参数为前端文件上传对象MultipartFile
     * 返回的是objectName 作为下载文件的依据，客服端需要存储
     *
     * @param file
     * @param fileObjectName 上传原始文件名
     */
    String uploadFileByInputStream(MultipartFile file, String fileObjectName, String contentType, Boolean isPrivate) throws UkuleleOSSException, IOException;

    String uploadFileByInputStream(MultipartFile file, String fileObjectName, Boolean isPrivate) throws UkuleleOSSException, IOException;

    String uploadFileByInputStream(InputStream inputStream, String fileObjectName, String ContentType, Boolean isPrivate) throws UkuleleOSSException;


    /**
     * 生成一个GET请求的分享链接。
     * 失效时间默认是7天。
     *
     * @param objectName 存储桶里的对象名称
     * @param expires    失效时间（以秒为单位），默认是7天，不得大于七天
     * @return url
     */
    String preSignedGetObject(String objectName, Integer expires) throws Exception;
    /**
     * 根据objectName获取公共桶访问的链接。
     *
     * @param objectName 存储桶里的对象名称
     * @return url
     */
    String pubGetObject(String objectName) ;

    /**
     * 复制文件
     *
     * @param sourcePath 源路径
     * @param targetPath 目标路径
     * @return
     * @throws UkuleleOSSException
     */
    String copyFile(String sourcePath, Boolean sourcePrivate, String targetPath, Boolean targetPrivate) throws UkuleleOSSException;

    /**
     * 根据fileObjectName下载文件流
     *
     * @param fileObjectName test.png
     * @return
     */
    byte[] downloadFile(String fileObjectName, Boolean isPrivate) throws UkuleleOSSException;

    void downloadFile(String fileObjectName, Boolean isPrivate, HttpServletResponse response) throws IOException;

    /**
     * 根据fileObjectName删除
     *
     * @param fileObjectName
     * @return
     */
    void deleteFile(String fileObjectName, Boolean isPrivate);

    void deleteFiles(List<String> fileObjectNames, Boolean isPrivate);
}
